<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>解析 python decorator  | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="解析 python decorator  | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2014/12/21/python-decorator/">

	
	<meta property="article:published_time" content="2014-12-21T00:12:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2014/12/21/python-decorator/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2014-12-20T16:00:00.000Z" itemprop="datePublished">
                    2014-12-21
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/程序技术/">程序技术</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">解析 python decorator </h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <p>首次看到 python 的 decorator 的时候，感到非常新奇，也非常困惑。这个看起来很酷，在各种源码里经常出现的家伙到底是什么意思，怎么使用？</p>
<pre><code>@myDecorator
def aFunction():
    print(&quot;inside a Function&quot;)
</code></pre><p>这篇文章就解释一下自己的这个疑惑。</p>
<h2 id="从函数开始"><a href="#从函数开始" class="headerlink" title="从函数开始"></a>从函数开始</h2><p>函数可以看做一个容器，它根据接受的参数进行运算，并返回出结果（没有返回的函数可以看做返回值是 <code>None</code> ）。</p>
<p><img src="http://t1.qpic.cn/mblogpic/a51abdb4aab5f9027162/460.jpg" alt=""></p>
<p>在 Python 这样的高级语言里面，函数还有另外一个身份：对象。这就说明函数不仅是动词（对值做运算的过程），也是名词（本身是可以使用的对象）。这样，函数就能像 <code>integers</code>, <code>strings</code>, <code>objects</code> 一样被传来传去。</p>
<p>想到这里的话，那可以把一个函数作为参数传给另外一个函数，或者函数的返回值也是一个函数啊！这就是理解 decorator 的基础和最关键的一点啦！</p>
<p>Decorator 就是这样一个函数：它接受一个函数作为参数，并返回一个函数作为返回值。</p>
<blockquote>
<p>A decorator is a function that takes a function object as an argument, and returns a function object as a return value.</p>
</blockquote>
<h2 id="走向-decorator"><a href="#走向-decorator" class="headerlink" title="走向 decorator"></a>走向 decorator</h2><p>下面是一个简单装饰器的定义：</p>
<pre><code>def verbose(func):

    def new_function(*args, **kwargs):
        print(&quot;Entering&quot;)
        func(*args, **kwargs)
        print(&quot;Exiting &quot;)

    return new_function
</code></pre><p>它在执行原来的函数前和执行后，各打印一句话。那怎么使用这个装饰器呢？很简单，根据前面的定义，传给它一个函数就行。</p>
<p>假如我们有一个 <code>hello world</code> 的函数：</p>
<pre><code>def hello_world():
    print(&quot;Hello,world!&quot;)
</code></pre><p>那么执行下面的语句</p>
<pre><code>v_hello_world = verbose(hello_world)
</code></pre><p>我们就得到一个 v_hello_world 的变量，根据前面的定义，这个变量是一个函数。<strong>需要注意的是，函数只有在遇到 <code>()</code> 符号的时候才会调用</strong>。我们新得到的函数还没有被调用，也就是说接下来可以调用它，让它执行定义的内容。</p>
<pre><code>v_hello_world()
</code></pre><p>这个时候会看到下面的输出：</p>
<pre><code>Entering hello_world
hello,world!
Exiting hello_world
</code></pre><p>其实可以不用引入新的变量，直接这样写：</p>
<pre><code>hello_world = verbose(hello_world)
</code></pre><p>这里 <code>verbose</code> 被称为装饰函数，它用来给原来的函数添加新的特性。</p>
<h2 id="符号"><a href="#符号" class="headerlink" title="@ 符号"></a>@ 符号</h2><p>为了更好地使用上述的特性，<code>Python</code> 提供了 <code>@</code> 这个<a href="http://en.wikipedia.org/wiki/Syntactic_sugar" target="_blank" rel="noopener">语法糖</a>。这样的话，上面的例子就可以简写为：</p>
<pre><code>@verbose
def hello_world():
    print(&quot;Hello,world!&quot;)
</code></pre><p>得到的就是被装饰后的函数。在刚开始不熟悉的时候，可以把装饰器还原成 <code>hello_world = verbose(hello_world)</code> 的形式，方便自己的理解。</p>
<h2 id="decorator-高级用法"><a href="#decorator-高级用法" class="headerlink" title="decorator 高级用法"></a>decorator 高级用法</h2><h3 id="嵌套（chained）的-decorator"><a href="#嵌套（chained）的-decorator" class="headerlink" title="嵌套（chained）的 decorator"></a>嵌套（chained）的 decorator</h3><p>事实上，decorator 是可以嵌套使用的，下面的代码来自 stackoverflow 的<a href="http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python/739665#739665" target="_blank" rel="noopener">这个答案</a>。</p>
<pre><code>def makebold(fn):
    def wrapped():
        return &quot;&lt;b&gt;&quot; + fn() + &quot;&lt;/b&gt;&quot;
    return wrapped

def makeitalic(fn):
    def wrapped():
        return &quot;&lt;i&gt;&quot; + fn() + &quot;&lt;/i&gt;&quot;
    return wrapped

@makebold
@makeitalic
def hello():
    return &quot;hello world&quot;

print hello() ## returns &lt;b&gt;&lt;i&gt;hello world&lt;/i&gt;&lt;/b&gt;
</code></pre><h3 id="带参数的-decorator"><a href="#带参数的-decorator" class="headerlink" title="带参数的 decorator"></a>带参数的 decorator</h3><p>除了可以嵌套使用之外，decorator 还能够带有参数。为了说明这个问题，假设有这样的场景：我们需要一个 decorator 把原来的函数执行多次。</p>
<p>如果要执行的次数是固定的，比如 3 次，问题还是很容易解决：</p>
<pre><code>def repeat3(func):
    &#39;&#39;&#39;
    execute original function three times
    &#39;&#39;&#39;
    def inner(*args, **kwargs):
        func(*args, **kwargs)
        func(*args, **kwargs)
        func(*args, **kwargs)

    return inner
</code></pre><p>如果要执行的次数不确定呢？我们就需要一个额外的参数，最终的目的就是下面的代码能够把 <code>hello_world</code> 函数执行 3 遍：</p>
<pre><code>@repeat(3)
hello_world():
    print(&quot;Hello,world!&quot;)
</code></pre><p>根据前面的定义，上面的代码等价于：</p>
<pre><code>hello_world = repeat(3)(hello_world)
</code></pre><p>那么 <code>repeat(3)</code> 的结果必须是一个函数，才能在后面被传参调用。不仅如此， <code>repeat(3)</code> 的结果接受的参数还是函数，那它应该也是 decorator。也就是说，<code>repeat</code> 是一个函数，它的返回值也是函数，并且返回的函数的参数和返回值都是函数。好吧，我也是晕了！还是看个例子吧：</p>
<pre><code>def repeat(n):
    def repeatn(f):
        def inner(*args, **kwargs):
            for i in range(n):
                f(*args, **kwargs)
        return inner
    return repeatn

@repeat(5)
def hello(name=&quot;world&quot;):
    print(&quot;Hello,%s&quot; % name)

hello()
</code></pre><p>再解释一遍，<code>repeat</code> 接受 5 作为参数，并返回一个 decorator —— <code>repeatn</code>，<code>repeatn</code> 返回一个把原来的函数执行 n 遍的函数。</p>
<h3 id="他们真的一样吗？"><a href="#他们真的一样吗？" class="headerlink" title="他们真的一样吗？"></a>他们真的一样吗？</h3><p>写到这里，我们已经知道：装饰器就是把原来的函数记作 f1 添加一些特性，然后生成一个新的函数 f2。然后，我们就可以想使用原函数 f1 那样使用 f2，不用在意内部的细节。但是这两个函数真的是一样的吗？<strong>答案是否定的</strong>。我们来看一下例子：</p>
<p>定义一个简单的函数，</p>
<pre><code>&gt;&gt;&gt; def bar():
...   &#39;&#39;&#39; This is bar function document &#39;&#39;&#39;
...   pass
</code></pre><p>查看 bar 函数的属性，</p>
<pre><code>&gt;&gt;&gt; bar.__name__, bar.__doc__, bar.__module__
(&#39;bar&#39;, &#39; This is bar function document&#39;, &#39;__main__&#39;)
</code></pre><p>使用 inspect 查看 bar 函数的参数定义，</p>
<pre><code>&gt;&gt;&gt; import inspect
&gt;&gt;&gt; inspect.getargspec(bar)
([], None, None, None)

&gt;&gt;&gt; bar2=verbose(bar)
&gt;&gt;&gt; bar2.__name__, bar2.__doc__, bar2.__module__
(&#39;shown&#39;, None, &#39;__main__&#39;)

&gt;&gt;&gt; inspect.getargspec(bar2)
([], &#39;args&#39;, &#39;kwargs&#39;, None)
</code></pre><p>好了，不难理解，原函数 f1 的属性并没有传递到新的函数 f2。那么 f1 的属性就不能使用了，而我们对 f2 的属性根本就不感兴趣。那么直接一点的方法就是把 f1 的属性拷贝到 f2：</p>
<pre><code>def verbose(func):
    def new_function(*args, **kwargs):
        print(&quot;Entering&quot;)
        func(*args, **kwargs)
        print(&quot;Exiting &quot;)


    new_function.__name__ = func.__name__
    new_function.__doc__ = func.__doc__
    new_function.__module__ = func.__module__
    new_function.__dict__.update(func.__dict__)

    return new_function


&gt;&gt;&gt; bar2=verbose(bar)
&gt;&gt;&gt; bar2.__name__, bar2.__doc__, bar2.__module__
(&#39;bar&#39;, &#39; This is bar function document &#39;, &#39;__main__&#39;)
</code></pre><p>Python2.5 以后的版本在 functools 提供了一个装饰器(没错，谁的问题谁负责)来解决 <code>wraps</code> 这个问题：</p>
<pre><code>&gt;&gt;&gt; from functools import wraps

&gt;&gt;&gt; def verbose(f):
...   @wraps(f)
...   def new_function(*args, **kwargs):
...     print(&quot;Entering&quot;)
...     func(*args, **kwargs)
...     print(&quot;Exiting &quot;)
...   return new_function

&gt;&gt;&gt; bar2=verbose(bar)
&gt;&gt;&gt; bar2.__name__, bar2.__doc__, bar2.__module__
(&#39;bar&#39;, &#39; This is bar function document&#39;, &#39;__main__&#39;)
</code></pre><h3 id="函数并不是唯一"><a href="#函数并不是唯一" class="headerlink" title="函数并不是唯一"></a>函数并不是唯一</h3><p>我们上面的文章一直在讲用函数实现的 decorator，其实函数并不是唯一的实现方式，利用类也能实现 decorator。让我们再次回到 decorator 的本质：</p>
<pre><code>my_func = decorator(my_func)
</code></pre><p>看到了没？decorator 是这样的东西（不一定是函数）：它<strong>可以被调用</strong>，接受一个函数作为参数，调用后会返回一个新的函数。你可能会问，这个东西除了函数还会是什么？答案就在下面两点：</p>
<ol>
<li>函数也是类，因为在 python 里一切都是对象</li>
<li>一个东西能被调用，是因为内部定义了 <code>__call__</code> 函数。如果我们自己写的类实现了这个特殊的函数，也能够被调用啦。</li>
</ol>
<p>好了，知道了原理，我们就来看看用类实现的 decorator，下面的代码来自于<a href="http://www.artima.com/weblogs/viewpost.jsp?thread=240808" target="_blank" rel="noopener">这篇文章</a>：</p>
<pre><code>class entryExit(object):
    def __init__(self, f):
        self.f = f

    def __call__(self):
        print &quot;Entering&quot;, self.f.__name__
        self.f()
        print &quot;Exited&quot;, self.f.__name__


class decoratorWithArguments(object):
    def __init__(self, arg1, arg2, arg3):
        &quot;&quot;&quot;
        If there are decorator arguments, the function
        to be decorated is not passed to the constructor!
        &quot;&quot;&quot;
        print &quot;Inside __init__()&quot;
        self.arg1 = arg1
        self.arg2 = arg2
        self.arg3 = arg3

    def __call__(self, f):
        &quot;&quot;&quot;
        If there are decorator arguments, __call__() is only called
        once, as part of the decoration process! You can only give
        it a single argument, which is the function object.
        &quot;&quot;&quot;
        print &quot;Inside __call__()&quot;
        def wrapped_f(*args):
            print &quot;Inside wrapped_f()&quot;
            print &quot;Decorator arguments:&quot;, self.arg1, self.arg2, self.arg3
            f(*args)
            print &quot;After f(*args)&quot;
        return wrapped_f

@decoratorWithArguments(&quot;hello&quot;, &quot;world&quot;, 42)
def sayHello(a1, a2, a3, a4):
    print &#39;sayHello arguments:&#39;, a1, a2, a3, a4

print &quot;After decoration&quot;

print &quot;Preparing to call sayHello()&quot;
sayHello(&quot;say&quot;, &quot;hello&quot;, &quot;argument&quot;, &quot;list&quot;)
print &quot;after first sayHello() call&quot;
sayHello(&quot;a&quot;, &quot;different&quot;, &quot;set of&quot;, &quot;arguments&quot;)
print &quot;after second sayHello() call&quot;
</code></pre><h2 id="decorator-实际中的使用"><a href="#decorator-实际中的使用" class="headerlink" title="decorator 实际中的使用"></a>decorator 实际中的使用</h2><p>花费了这么多的精力和脑细胞学习这个很炫的东西，那么 decorator 在实际的编码中到底有哪些用呢？这个嘛，用处可多了！</p>
<p>比如，稍微修改一下上面例子的代码，就能写一个函数的计时器：</p>
<pre><code>def timer(func):
    &quot;&quot;&quot; A decorator to print the time function executes &quot;&quot;&quot;
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        elapse = (time.time() - start) * 1000
        print &quot;func %s elapsed time: %f ms&quot; % (func.__name__, elapse)

@timer
foo():
    do_something()
</code></pre><p>又比如，上面提过的 <a href="http://stackoverflow.com/a/1594484/1925083" target="_blank" rel="noopener">stackoverflow 的帖子</a>也给出了类似的 benchmark，counter，logging 装饰器。</p>
<pre><code>def logging(func):
    &quot;&quot;&quot;
    A decorator that logs the activity of the script.
    (it actually just prints it, but it could be logging!)
    &quot;&quot;&quot;
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print func.__name__, args, kwargs
        return res
    return wrapper


def counter(func):
    &quot;&quot;&quot;
    A decorator that counts and prints the number of times a function has been executed
    &quot;&quot;&quot;
    def wrapper(*args, **kwargs):
        wrapper.count = wrapper.count + 1
        res = func(*args, **kwargs)
        print &quot;{0} has been used: {1}x&quot;.format(func.__name__, wrapper.count)
        return res
    wrapper.count = 0
    return wrapper
</code></pre><p>Python 自带的 decorator 就有 <code>staticmethod</code> 和 <code>property</code>。除此之外，你还可以在<a href="https://wiki.python.org/moin/PythonDecoratorLibrary" target="_blank" rel="noopener">这个 wiki </a>上面查看更多的实例。</p>
<p>最后，更多的实例就要等你在实际中开发啦！</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="http://pythonconquerstheuniverse.wordpress.com/2012/04/29/python-decorators/" target="_blank" rel="noopener">Python Decorators</a></li>
<li><a href="http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/" target="_blank" rel="noopener">Understanding Python Decorators in 12 Easy Steps!</a></li>
<li><a href="http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python/1594484#1594484" target="_blank" rel="noopener">How can I make a chain of function decorators in Python?</a></li>
<li><a href="https://wiki.python.org/moin/PythonDecoratorLibrary" target="_blank" rel="noopener">Python Decorator Library</a></li>
<li><a href="http://kentsjohnson.com/kk/00001.html" target="_blank" rel="noopener">Decorators by Kent S Johnson</a></li>
<li><a href="https://docs.python.org/2/library/functools.html#functools.wraps" target="_blank" rel="noopener">functools.wraps</a></li>
<li><a href="http://thecodeship.com/patterns/guide-to-python-function-decorators/" target="_blank" rel="noopener">A guide to Python’s function decorators</a></li>
</ul>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="linux 系统启动过程" href="/2015/01/18/linux-boot-process/">
        ← linux 系统启动过程
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="Sublime Text: python 程序员不完全指南" href="/2014/12/20/sublime-tutorial-for-pythoner/">
        Sublime Text: python 程序员不完全指南 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#从函数开始"><span class="toc-text">从函数开始</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#走向-decorator"><span class="toc-text">走向 decorator</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#符号"><span class="toc-text">@ 符号</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#decorator-高级用法"><span class="toc-text">decorator 高级用法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#嵌套（chained）的-decorator"><span class="toc-text">嵌套（chained）的 decorator</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#带参数的-decorator"><span class="toc-text">带参数的 decorator</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#他们真的一样吗？"><span class="toc-text">他们真的一样吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数并不是唯一"><span class="toc-text">函数并不是唯一</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#decorator-实际中的使用"><span class="toc-text">decorator 实际中的使用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考资料"><span class="toc-text">参考资料</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">解析 python decorator </div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2014/12/21/python-decorator/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2014/12/21/python-decorator/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
